/*******************************************
 * small function for search the files which satify the pattern
 *******************************************/
#include <stdio.h>  
#include <string.h> 
#include <stdlib.h>  
#include <dirent.h>  
#include <sys/stat.h>  
#include <unistd.h>  
#include <sys/types.h> 

#include <fnmatch.h>

#define MAX_FILE  1024*8
#define NAME_LENGTH 1024





//input parse
int  have_symbolic=0;  //flag for deciding symbolic link directory
char *pattern;
int pattern_ret;
char * search_path_name;
void input_parse(int argc, char *argv[]);//input parse and standand


char * symbolic_name_to_hard_name(char * symbolic_name);//from symbolic name to absolute name
void regurlar_file_right_and_size(char* path_name); //from absolute path name to get information for printing out

char  find_file[MAX_FILE][NAME_LENGTH];//the find file storage string array
int find_file_length = 0;  //the find file index and length 
void sort_str_array(char array[MAX_FILE][NAME_LENGTH],int n) ;  //sort string array char  str[MAX_FILE][NAME_LENGTH];

 void recursive_dir(char *path)   //Recursive directory
 {  
         DIR              *pDir ;  
         struct dirent    *dirp  ;   
         int               i=0  ;  
         char              childpath[NAME_LENGTH];
     struct stat buf;
	 char *path_name;
   
         pDir=opendir(path);  
         memset(childpath,0,sizeof(childpath)); 
         while((dirp=readdir(pDir))!=NULL) 
         {  	   
	   if(dirp->d_type & DT_DIR)  // directory and not symbolic directory
                 {     
                         if(strcmp(dirp->d_name,".")==0 || strcmp(dirp->d_name,"..")==0)                                       
                                 continue;  
                         sprintf(childpath,"%s/%s",path,dirp->d_name);  
                         //printf("path:================%s\n",childpath);  
                         recursive_dir(childpath); //Recursive calling self to travel in directory 
                 }else
		 if( (dirp->d_type == DT_LNK ) &  (have_symbolic) ){ //symbolic link ,two possible:directory and plain file.
		   sprintf(childpath,"%s/%s",path,dirp->d_name);  		   		   
		   //symbolic to hard path name
		   path_name=symbolic_name_to_hard_name(childpath);
		   int len=0;
		   len = strlen(path_name);
		   path_name[len-1]='\0';
		    //printf("%s is symbolic\n",path_name);
		   
		  
		   int symbolic_dir = 0;
		   struct stat sb;		    
		    if(stat(childpath, &sb) == -1){
		      perror("stat");
		      exit(EXIT_FAILURE);
		    }
		    
		    if( (sb.st_mode & S_IFMT) == S_IFDIR)
		      symbolic_dir = 1;// the symbolic link  points to dir.
		      
		   if(symbolic_dir){	//symbolic link is directory	   
		     recursive_dir(childpath);
		   }else{ //symbolic link is plain file
		     
			//match pattern
			pattern_ret = fnmatch(pattern, dirp->d_name, FNM_PATHNAME|FNM_PERIOD);
			if(pattern_ret == 0){
			  sprintf(childpath,"%s/%s",path,dirp->d_name);
			  sprintf(find_file[find_file_length],"%s",childpath);
			  find_file_length++;	      
			}else 
			  if(pattern_ret == FNM_NOMATCH){
			    continue;
			  }else{
			    printf("error file=%s\n", dirp->d_name);
			  }
		  }
		   
		}else  
               {
		    /*if(strcmp(dirp->d_name,"t.c") == 0 ){
		      sprintf(childpath,"%s/%s",path,dirp->d_name);
		      regurlar_file_right_and_size(childpath);
		    }*/
		   
		    int symbolic_dir = 0;
		    struct stat sb;
		    sprintf(childpath,"%s/%s",path,dirp->d_name);
		    if(stat(childpath, &sb) == -1){
		      perror("stat");
		      exit(EXIT_FAILURE);
		    }
		    
		    if( (sb.st_mode & S_IFMT) == S_IFDIR)
		      symbolic_dir = 1;// the symbolic link is point to dir.
		    if(symbolic_dir){		   
		      continue;
		    }else{
			//match pattern
			pattern_ret = fnmatch(pattern, dirp->d_name, FNM_PATHNAME|FNM_PERIOD);
			if(pattern_ret == 0){
			  sprintf(childpath,"%s/%s",path,dirp->d_name);
			  sprintf(find_file[find_file_length],"%s",childpath);
			  find_file_length++;	      
			}else 
			  if(pattern_ret == FNM_NOMATCH){
			    continue;
			  }else{
			    printf("error file=%s\n", dirp->d_name);
			  }
		   }
		 
               }
         }  
         
 }
 
 //**************************************************************************************  
 int main(int argc,char *argv[])  
 {  
   int i=0;
   
   input_parse(argc,argv);
   recursive_dir(search_path_name); 
   i=0;
   
   sort_str_array(find_file,find_file_length);
   
   for(i=0;i<find_file_length;i++)
   {
     //printf("%s\n",find_file[i]);
     regurlar_file_right_and_size(find_file[i]);
  }
           
   return 0;  
 }
 //***************************************************************************************
 
void sort_str_array(char array[MAX_FILE][NAME_LENGTH],int n)   //sort char * str[];
{

    char temp[MAX_FILE];

    int i,j,k;

    for(i=0;i<n-1;i++)
    {
        k=i;
        for(j=i+1;j<n;j++)
            if(strcmp(array[k],array[j])>0)
	      k=j;
        if(k!=i)
        {
            strcpy(temp,array[i]);  
            strcpy(array[i],array[k]);
            strcpy(array[k],temp);
        }
    }
    
    
} 
 

 void input_parse(int argc, char *argv[])
{
    // input parse;
    int i=0;
    int have_pattern = 0;
    printf("argc:%d\n",argc);

    for(i=1 ;i<argc ;i++ ){
      // symbolic link 
      //printf("argv[%d]:%s\n",i,argv[i]);
      if(strcmp(argv[i], "-L") == 0 ){
	have_symbolic = 1;
	
      }else if(strcmp(argv[i], "-n") == 0 ){
	pattern = argv[i+1];
	have_pattern = 1;
	//printf("the search_name pattern:%s\n",pattern);
      }else if(strcmp(argv[i], "-h") == 0 ){
	printf("usage: %s [-h] [-n NAME] [-L] path\n",argv[0]);
      }
           
    }
    //printf("have_symbolic:%d\n",have_symbolic);
    if(!have_pattern)
      pattern = "*";
    
    if(argc > 1){
	search_path_name = argv[argc-1];
	int len=0;
	len = strlen(search_path_name);
	if(search_path_name[len-1]=='/'){
	  search_path_name[len-1] = '\0';
	}
    }
    //printf("the search_path_name:%s\n",search_path_name);
  
}



char * symbolic_name_to_hard_name(char * symbolic_name)
{
  struct stat sb;
  char *linkname;
  ssize_t read_link;
  
  if(lstat(symbolic_name, &sb) == -1){
    //perror("lstat");
    printf("lstat ,some error\n");
    exit(EXIT_FAILURE);
  }
  
  linkname = malloc(sb.st_size + 1);
  if(linkname == NULL){
    fprintf(stderr, "insufficient memory\n");
    exit(EXIT_FAILURE);
  }
  
  read_link = readlink(symbolic_name, linkname, sb.st_size + 1);
  
  if(read_link == -1){
    //perror("lstat");
    printf("read_link error !\n");
    exit(EXIT_FAILURE);
  }
  if (read_link > sb.st_size) {
               fprintf(stderr, "symlink increased in size "
                               "between lstat() and readlink()\n");
               exit(EXIT_FAILURE);
  }
  
  linkname[read_link] = '\0';
  
  //printf("'%s' points to '%s'\n",symbolic_name, linkname);
  
  return linkname; 
}

// to decide the rwx right of regular file
void regurlar_file_right_and_size(char* path_name)
{
  struct stat sb;
  int file_size=0;
  int mode=0;
  char right[]="---------";
  
  if(lstat(path_name, &sb) == -1){
    perror("lstat");
    exit(EXIT_FAILURE);
  }
  
  file_size  = sb.st_size;
  
  mode = sb.st_mode;
  
  int off=0;
  
  if(mode & S_IRUSR) right[0+off] = 'r';
  if(mode & S_IWUSR) right[1+off] = 'w';
  if(mode & S_IXUSR) right[2+off] = 'x';
  
  if(mode & S_IRGRP) right[3+off] = 'r';
  if(mode & S_IWGRP) right[4+off] = 'w';
  if(mode & S_IXGRP) right[5+off] = 'x';
  
  if(mode & S_IROTH) right[6+off] = 'r';
  if(mode & S_IWOTH) right[7+off] = 'w';
  if(mode & S_IXOTH) right[8+off] = 'x';
  printf("%s %d %s\n",right,file_size,path_name);
  
  //sprintf(find_file[find_file_length],"%s",path_name);
  
  //find_file_length++;
  //printf("find_file:%s\n",find_file[find_file_length-1]);
 
} 
 
 
 
 